package Leetcode.网格图;

/**
 * @Author: kirito
 * @Date: 2024/5/3 13:58
 * @Description:
 * 扫雷游戏
 * 中等
 * 相关标签
 * 相关企业
 * 让我们一起来玩扫雷游戏！
 *
 * 给你一个大小为 m x n 二维字符矩阵 board ，表示扫雷游戏的盘面，其中：
 *
 * 'M' 代表一个 未挖出的 地雷，
 * 'E' 代表一个 未挖出的 空方块，
 * 'B' 代表没有相邻（上，下，左，右，和所有4个对角线）地雷的 已挖出的 空白方块，
 * 数字（'1' 到 '8'）表示有多少地雷与这块 已挖出的 方块相邻，
 * 'X' 则表示一个 已挖出的 地雷。
 * 给你一个整数数组 click ，其中 click = [clickr, clickc] 表示在所有 未挖出的 方块（'M' 或者 'E'）中的下一个点击位置（clickr 是行下标，clickc 是列下标）。
 *
 * 根据以下规则，返回相应位置被点击后对应的盘面：
 *
 * 如果一个地雷（'M'）被挖出，游戏就结束了- 把它改为 'X' 。
 * 如果一个 没有相邻地雷 的空方块（'E'）被挖出，修改它为（'B'），并且所有和其相邻的 未挖出 方块都应该被递归地揭露。
 * 如果一个 至少与一个地雷相邻 的空方块（'E'）被挖出，修改它为数字（'1' 到 '8' ），表示相邻地雷的数量。
 * 如果在此次点击中，若无更多方块可被揭露，则返回盘面。
 *
 *
 * 示例 1：
 *
 *
 * 输入：board = [["E","E","E","E","E"],["E","E","M","E","E"],["E","E","E","E","E"],["E","E","E","E","E"]], click = [3,0]
 * 输出：[["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]]
 * 示例 2：
 *
 *
 * 输入：board = [["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]], click = [1,2]
 * 输出：[["B","1","E","1","B"],["B","1","X","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]]
 *
 *
 * 提示：
 *
 * m == board.length
 * n == board[i].length
 * 1 <= m, n <= 50
 * board[i][j] 为 'M'、'E'、'B' 或数字 '1' 到 '8' 中的一个
 * click.length == 2
 * 0 <= clickr < m
 * 0 <= clickc < n
 * board[clickr][clickc] 为 'M' 或 'E'
 */

public class updateBoard {
    // 定义方向数组，用于上下左右以及斜向的八个方向
    int[] dirX = {0, 1, 0, -1, 1, 1, -1, -1};
    int[] dirY = {1, 0, -1, 0, 1, -1, 1, -1};

    public char[][] updateBoard(char[][] board, int[] click) {
        // 获取点击的位置
        int x = click[0], y = click[1];
        // 如果点击的是怪物
        if (board[x][y] == 'M') {
            // 将该位置更新为陷阱
            board[x][y] = 'X';
        } else {
            // 否则进行深度优先搜索
            dfs(board, x, y);
        }
        // 返回更新后的棋盘
        return board;
    }

    public void dfs(char[][] board, int x, int y) {
        // 初始化怪物计数器
        int cnt = 0;
        // 遍历所有可能的移动方向
        for (int i = 0; i < 8; ++i) {
            int tx = x + dirX[i];
            int ty = y + dirY[i];
            // 如果移动后的位置越界，则跳过该方向
            if (tx < 0
            || tx >= board.length
            || ty < 0
            || ty >= board[0].length) {
                continue;
            }
            // 如果遇到怪物，则增加计数器
            if (board[tx][ty] == 'M') {
                ++cnt;
            }
        }
        // 如果怪物计数器大于0，则将当前位置更新为怪物数量的字符
        if (cnt > 0) {
            board[x][y] = (char) (cnt + '0');
        } else {
            // 否则，将当前位置更新为宝藏
            board[x][y] = 'B';
            // 遍历所有可能的移动方向
            for (int i = 0; i < 8; ++i) {
                int tx = x + dirX[i];
                int ty = y + dirY[i];
                // 如果移动后的位置越界或已经不是空地，则跳过该方向
                if (tx < 0
                || tx >= board.length
                || ty < 0
                || ty >= board[0].length
                || board[tx][ty] != 'E') {
                    continue;
                }
                // 否则递归搜索
                dfs(board, tx, ty);
            }
        }
    }

}
